package com.doodle.common.utils;

import android.content.Context;
import android.graphics.drawable.Drawable;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;

import com.doodle.common.data.AsyncResource;
import com.doodle.common.data.DataAdapter;
import com.doodle.common.drawable.AsyncDrawable;

import java.util.List;

public abstract class BaseMediaAdapter<T> extends BaseListAdapter<T> implements OnScrollListener, DataAdapter {
	
	public interface AdapterCallBack {
		public abstract void onScrollToBottom();
	}
	
	/**
	 * 默认缓存16
	 */
	private int mCacheSize = 16;
	
	protected SlidingWindow mSlidingWindow;
	private AsyncDrawableJobExecutor mJobExecutor;
	private AsyncDrawable mDrawables[];
	private AdapterCallBack mCallBack;
	
	private AsyncDrawable mFirstDrawable;
	
	public BaseMediaAdapter(Context context, List<T> dataList, int cacheSize) {
		mContext = context;
		mCacheSize = cacheSize;
		mJobExecutor = AsyncDrawableJobExecutor.getInstance();
		mDrawables = new AsyncDrawable[mCacheSize * 2];
		mDataList = dataList;
		mSlidingWindow = new SlidingWindow(this, mCacheSize);
	}
	
	public void setCallBack(AdapterCallBack callback) {
		mCallBack = callback;
	}
	
	@Override
	public void swapData(List<T> dataList) {
		mSlidingWindow.beforeDataChanged();
		super.swapData(dataList);
		mSlidingWindow.afterDataChanged(dataList == null ? 0 : dataList.size());
	}

	@Override
	public int size() {
		return getCount();
	}

	@Override
	public void prepare(int index) {
		if (index == 0) {
			if (mFirstDrawable == null) {
				mFirstDrawable = createDrawable(0, mJobExecutor);
			}
		} else {
			int modIndex = index % mDrawables.length;
			AsyncDrawable drawable = mDrawables[modIndex];
			if (drawable == null) {
				mDrawables[modIndex] = createDrawable(index, mJobExecutor);
			}
		}
	}

	@Override
	public int start(int index) {
		AsyncDrawable drawable = index == 0 ? mFirstDrawable : mDrawables[index % mDrawables.length];
		if (drawable != null) {
			drawable.startLoad();
			return drawable.isRequestInProgress() ? 1 : 0;
		} else {
			Utils.log("Data start but not prepared: %d", index);
			return 0;
		}
	}

	@Override
	public void cancel(int index) {
		AsyncDrawable drawable = index == 0 ? mFirstDrawable : mDrawables[index % mDrawables.length];
		if (drawable != null) {
			drawable.cancelLoad();
		} else {
			Utils.log("Data cancel but not prepared: %d", index);
		}
	}

	@Override
	public void free(int index) {
		if (index == 0) {
			if (mFirstDrawable != null) {
				mFirstDrawable.recycle();
				mFirstDrawable = null;
			}
		} else {
			int modIndex = index % mDrawables.length;
			AsyncDrawable drawable = mDrawables[modIndex];
			if (drawable != null) {
				drawable.recycle();
			} else {
				Utils.log("Data free but not prepared: %d", index);
			}
			mDrawables[modIndex] = null;
		}
	}

	@Override
	public void remove(int index) {
	}

	@Override
	public void onScrollStateChanged(AbsListView view, int scrollState) {
		if (view.getLastVisiblePosition() == view.getCount() - 1) {
			if (mCallBack != null) {
				mCallBack.onScrollToBottom();
			}
		}
	}
	
	@Override
	public void onScroll(AbsListView view, int firstVisibleItem,
			int visibleItemCount, int totalItemCount) {
		if (view instanceof ListView) {
			firstVisibleItem -= ((ListView)view).getHeaderViewsCount();
		}
		int end = firstVisibleItem + visibleItemCount;
		end = Math.min(end, size());
		firstVisibleItem = Math.max(firstVisibleItem, 0);
		mSlidingWindow.setVisibleWindow(firstVisibleItem, end);
	}
	
	public AsyncDrawable getDrawable(int index) {
		if (index == 0) {
			if (mFirstDrawable == null) {
				mFirstDrawable = createDrawable(0, mJobExecutor);
			}
			return mFirstDrawable;
		} else {
			int modIndex = index % mDrawables.length;
			AsyncDrawable drawable =  mDrawables[modIndex];
			if (drawable == null) {
				drawable = createDrawable(index, mJobExecutor);
				mDrawables[modIndex] = drawable;
			} else {
			}
			return drawable;
		}
	}
	
	@Override
	public long getDataId(int index) {
		return getItemId(index);
	}

	@Override
	public Object getDataObject(int index) {
		return index == 0 ? mFirstDrawable : mDrawables[index % mDrawables.length];
	}
	
	@Override
	public void setDataObject(int index, Object data) {
		if (index == 0) {
			mFirstDrawable = (AsyncDrawable)data;
		} else {
			mDrawables[index % mDrawables.length] = (AsyncDrawable)data;
		}
	}
	
	@Override
	public void freeDataObject(Object data) {
		if (data != null) {
			((AsyncDrawable)data).recycle();
		}
	}
	
	public void clearDrawables() {
		for (int i = 0; i < mDrawables.length; i++) {
			mDrawables[i] = null;
		}
		mFirstDrawable = null;
	}
	
	
	protected abstract AsyncDrawable createDrawable(int index, AsyncResource.JobExecutor<Drawable> jobExecutor);
}
